var TableEditor = function(path) {
	/* 
		Public Interface/Data
	*/
	this.isRenderable = function () { return items.length == 0 ? false : true; };
	this.renderIntoElement = function (element, title) {
		if (!this.isRenderable)
			return new Element('div', { text: 'No data' });
			
		var target = document.id(element),
			topBar = new Element('div', { 'id': 'header' }).grab(new Element('h2', { 'text': title })),
			tablePane = new Element('div', { 'id': 'pane' }),
			bottomBar = new Element('div', { 
				'id': 'footer'
			}),
			controlProperties = {
					'type': 'button',
					'value': 'Save Changes',
					'id': 'saveAll',
					'disabled': true,
					'events': {
						'click': function() {
							this.saveAll();
						}.bind(this)
					},
					'styles': {
						'margin-left': '2em',
						'float': 'left'
					}
			};
		bottomBar.grab(new Element('input', controlProperties));
		
		if(target && table)
			tablePane.grab(table);
		target.grab(topBar);
		target.grab(tablePane);
		target.grab(bottomBar);
		resizeHeaderlessContent();
		sharpRegistry.activePanes['table'] = this;
	};
	this.resize = function() {
		resizeHeaderlessContent();
	}
	this.saveAll = function() {
		var changed = $$('.dirty');
		if (changed)
			store.commitRows(changed);
	};
	
	this.headings = new Hash();
	
	/*
		Private Interface/Data
	*/
	var applicationUrl = sharpbar.applicationUrl + "/",
		headings = this.headings,
		providers = new Hash(),
		store = new WebDAVStore(applicationUrl,
			function(data, targetId, xml) { // commit hook
				data.getKeys().length == 0 ? document.id('saveAll').disabled = true : document.id('saveAll').disabled = false;
				var targetElement = document.id(targetId),
					response = XML.getValueForTag(xml, 'D:responsedescription');
				targetElement.getElements('input').setStyle('display', 'none');
				
				if (response.contains('Successfully')) {
					// set green, then fade out
					if (targetElement.hasClass('save-failure'))
						targetElement.removeClass('save-failure');
						
				} else {
					// set red
					targetElement.addClass('save-failure');
					targetElement.tip = response;
					targetElement.title = "Error:";
					
					// Is this a memory leak?
					new Tips(targetElement, {
						'text': function(el) {
							return el.tip;
						}
					});
				}
				
			},
			function(data, targetId) { // notify hook
				data.getKeys().length != 0 ? document.id('saveAll').disabled = false : document.id('saveAll').disabled = true;
				document.id(targetId).getElements('input').setStyle('display', 'block');
			}
		),
		table = new HtmlTable({
			properties: {
				border: 1
				// cellspacing: 3,
				//id: 'itemTable',
			},
			editable: true,
			store: store,
			providerList: providers
		}),
		initialize = function(url) {
			if (providers)
				providers.empty();
			mc.propfind(url, function(xml, text) {
				var xmlItems = XML.getElementsArrayByTagName(xml, 'D:response'),
					childItems = xmlItems.slice(1);
				if (childItems && childItems.length > 0) {
					headings['Name'] = true;
					headings['Published'] = true;
					childItems.each(function(childItem) {
						var provider = XML.getValueForTag(childItem, 'mc:resourceprovider');
						if (provider && !providers.has(provider)) {
							mc.report(sharpbar.applicationUrl, 'specification-details', function(xml) { 
								var properties = XML.getElementsArrayByTagName(xml, 'Property'),
									spec = new Hash();
								properties.each(function(property) {
									var propertyName = property.getAttribute('Label') || XML.getElementsArrayByTagName(xml, 'Name'),
										type = property.getAttribute('DisplayType').toLowerCase(),
										values = property.getAttribute('ValidValues');
									if (propertyName != null && propertyName != 'Published') {
										headings[propertyName] = true;
									}
									if (type == 'select' || type == 'multiselect' || type == 'radio') {
										if (values) {
											spec.values = new Array();
											values.trim().split(',').each(function(value) {
												var v = value.trim();
												if (v)
													spec.values.push(v);
											});
										}
									}
								});
								if (spec)
									providers[provider] = spec;
								else
									providers[provider] = true;
							}, true, provider);
						}
					});
					table.setHeaders(headings.getKeys());
					childItems.each(function(childItem) {						
						mc.propfind(applicationUrl + XML.getValueForTag(childItem, 'D:href'), function(xml, text) {
							var childItems = XML.getElementsArrayByTagName(xml, 'D:response'),
								firstChild = childItems.length > 0 ? childItems[0] : null,
								row = new Array(),
								item = new Item(firstChild),
								buttonsElement = new Element('span').addClass('buttons');
								
							if(firstChild && item) {						
								headings.getKeys().each(function(key) { 
									if (item.fields.has(key) && item.fields[key].value) {
										var computedClass = item.fields[key].displayType.toLowerCase() + ' ' + item.fields[key].tagClass;
										computedClass += item.fields[key].userEditable == false ? ' readonlycell' : '';
										
										row.push({ 
											content: item.fields[key].value, 
											properties: { 
												'class': 'minwidth ' + computedClass, 
												'itemId': item.metadata.id, 
												'itemUrl': applicationUrl + item.metadata.href, 
												'itemTag': item.fields[key].tagName, 
												'mcsNS': item.metadata.mcsNS,
												'providerId': item.metadata.providerId
											}
										});
									} else {
										var computedClass = item.fields[key] ? item.fields[key].displayType.toLowerCase() + ' ' + item.fields[key].tagClass : '';
										computedClass += computedClass != '' && item.fields[key].userEditable == false ? ' readonlycell' : '';
										row.push({ 
											content: '&nbsp;', //new Element('input', {'type': 'checkbox', 'checked': true, 'disabled': true}),
											properties: { 
												'class': item.fields[key] ? 'minwidth ' + item.fields[key].displayType.toLowerCase() + ' ' + item.fields[key].tagClass : '', 
												'itemId': item.metadata.id, 
												'itemUrl': applicationUrl + item.metadata.href, 
												'itemTag': item.fields[key] ? item.fields[key].tagName : '', 
												'mcsNS': item.metadata.mcsNS,
												'providerId': item.metadata.providerId												
											}
										});	
									}
								});

								buttonsElement.grab(new Element('input', { 
									'type': 'button', 
									'value': 'Save', 
									'events': {
										'click': function() {
											var cell = this.getParent().getParent(),
												row = cell.getParent(),
												id = cell.getAttribute('itemid');
											store.commit(id, row);
										}
									},
									'styles': {
										'display': 'none'
									}
								}));

								row.push({
									content: buttonsElement, 
									properties: {
										'itemId': item.metadata.id, 
										'itemUrl': applicationUrl + item.metadata.href, 
										'mcsNS': item.metadata.mcsNS 
									}
								});
								
								table.push(row, {'id': item.metadata.id});
							}
						});
					});
				}
			});
		}.bind(this);
	
	/*
		Initialize
	*/
	
	initialize(path);
}

var WebDAVStore = function(mcUrl, commitHook, notifyHook) {
	var rootUrl = mcUrl,
		data = new Hash(),
		ensureInitialized = function(key, subkey, namespace) {
			if (!data.has(key))
				data[key] = new Hash({'namespace': namespace, 'changes': new Hash()});
			
			if (!data[key].changes.has(subkey))
				data[key].changes[subkey] = new Array();
		},
		commitHook = commitHook,
		notifyHook = notifyHook;
		
	this.notify = function(element) {
		var	itemId = element.get('itemId'),
			xmlKey = element.get('itemTag'),
			ns = element.get('mcsNS');
			
		ensureInitialized(itemId, xmlKey, ns);

		data[itemId].changes[xmlKey].push(['innerText', element.get('text')]);
		if (notifyHook)
			notifyHook(data, itemId);
	};
	
	this.commit = function(id, row) {
		if (id) {
			var item = data[id]
			mc.proppatch(rootUrl + id, function(xml) {
				data.erase(id);
				if (row)
					row.removeClass('dirty');
					
				if (commitHook)
					commitHook(data, id, xml);
			}, item.changes, null, item.namespace);
		} 
	};
	
	this.commitRows = function(rows) {
		rows.each(function(row) {
			var children = row.getChildren(),
				id = children[0].get('itemid'),
				item = data[id];

			if (item) {
				mc.proppatch(rootUrl + id, function(xml) {
					row.removeClass('dirty');
					if (commitHook)
						commitHook(data, id, xml);	
				}, item.changes, null, item.namespace);
			}
		});
	}
}